package com.gaga.console.core.service.impl;

import cn.hutool.core.util.ArrayUtil;
import com.gaga.common.constant.BvConstants;
import com.gaga.common.enums.DelFlag;
import com.gaga.common.enums.ScriptItemFileType;
import com.gaga.common.enums.ScriptType;
import com.gaga.common.exception.BusException;
import com.gaga.console.base.mybatisplus.LambdaQueryWrapperExt;
import com.gaga.console.base.service.impl.SuperServiceImpl;
import com.gaga.console.base.utils.ZipFileUtil;
import com.gaga.console.core.entity.BvScriptCategory;
import com.gaga.console.core.entity.BvScriptItem;
import com.gaga.console.core.mapper.BvScriptCategoryMapper;
import com.gaga.console.core.service.BvScriptCategoryService;
import com.gaga.console.core.service.BvScriptItemService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author liujia
 * @since 2025-03-27
 */
@Service
@Slf4j
public class BvScriptCategoryServiceImpl extends SuperServiceImpl<BvScriptCategoryMapper, BvScriptCategory> implements BvScriptCategoryService {

    @Autowired
    private BvScriptItemService bvScriptItemService;

    @Override
    public void importCategory(MultipartFile file, HttpServletRequest request) {
        try {
            if (file == null) {
                throw new BusException("文件不存在");
            }

            String filename = file.getOriginalFilename();

            assert filename != null;
            if (filename.endsWith(BvConstants.FILE_SUFFIX_ZIP) || filename.endsWith(BvConstants.FILE_SUFFIX_7Z)) {
                //资源根目录
                String staticClasspath = ResourceUtils.getURL("classpath:").getPath();
                String fileDirId = String.valueOf(System.currentTimeMillis());
                //临时目录
                String tempPath = staticClasspath + BvConstants.PATH_UPLOAD + File.separator + BvConstants.PATH_IMPORT + File.separator + fileDirId;
                File tempDir = new File(tempPath);
                //先删除后增加
                FileUtils.deleteDirectory(tempDir);
                FileUtils.forceMkdir(tempDir);

                Path sourcesPath = Paths.get(tempDir.getAbsolutePath());
                Path tempFile = Files.createTempFile(sourcesPath, "", file.getName());
                //1.上传文件zip包
                file.transferTo(tempFile.toFile());

                //2.读取json文件，更新数据库数据
                Map<String, String> files = ZipFileUtil.readZipFileToMapWithWrap(tempFile.toFile());

                //3.解析zip文件包，将解压的文件放置到临时文件目录下
                ZipFileUtil.zipToFile(tempFile.toFile(), tempPath + "/");


                Set<String> categorySet = files.keySet().stream().filter(item -> item.contains("/"))
                        .map(item -> {
                            String[] split = item.split("/");
                            return split[0];
                        }).collect(Collectors.toSet());

                BvScriptCategory bvScriptCategory = new BvScriptCategory();
                bvScriptCategory.setScriptCategoryName(new ArrayList<>(categorySet).get(0));
                save(bvScriptCategory);

                List<BvScriptItem> insertList = new ArrayList<>();
                for (Map.Entry<String, String> entry : files.entrySet()) {
                    String[] keys = entry.getKey().split("/");

                    // 验证路径格式有效性
                    if (keys.length < 2 || !bvScriptCategory.getScriptCategoryName().equals(keys[0])) {
                        log.error("路径格式错误，或者品类名称不一样，跳过条目：" + entry.getKey());
                        continue;
                    }
                    String type = keys[1];          // 话术类型
                    ScriptType scriptTypeByInfo = ScriptType.getScriptTypeByInfo(type);
                    if (scriptTypeByInfo == null) {
                        continue;
                    }

                    if (keys.length == 2) {
                        BvScriptItem bvScriptItem = new BvScriptItem();
                        bvScriptItem.setScriptCategoryId(bvScriptCategory.getId());
                        bvScriptItem.setScriptType(scriptTypeByInfo.getCode());
                        bvScriptItem.setScriptContent(entry.getValue());
                        bvScriptItem.setItemName(type);
                        bvScriptItem.setItemFileType(ScriptItemFileType.getScriptItemTypeByCode(bvScriptItem.getItemName()).getCode());
                        insertList.add(bvScriptItem);
                    } else if (keys.length == 3) {
                        BvScriptItem bvScriptItem = new BvScriptItem();
                        bvScriptItem.setScriptCategoryId(bvScriptCategory.getId());
                        bvScriptItem.setScriptType(scriptTypeByInfo.getCode());
                        bvScriptItem.setItemName(keys[2]);
                        ScriptItemFileType scriptItemType = ScriptItemFileType.getScriptItemTypeByCode(bvScriptItem.getItemName());
                        bvScriptItem.setItemFileType(scriptItemType.getCode());
                        if (ScriptItemFileType.TXT.equals(scriptItemType)) {
                            bvScriptItem.setScriptContent(entry.getValue());
                        } else {
                            //视频文件路径
                            bvScriptItem.setScriptContent(tempPath + File.separator + entry.getKey());
                        }
                        insertList.add(bvScriptItem);
                    } else if (keys.length == 4 && ScriptType.MAIN_AUDIO.equals(scriptTypeByInfo)) {
                        BvScriptItem bvScriptItem = new BvScriptItem();
                        bvScriptItem.setScriptCategoryId(bvScriptCategory.getId());
                        bvScriptItem.setScriptType(scriptTypeByInfo.getCode());
                        //主音频下面的文件夹名称
                        bvScriptItem.setItemName(keys[2]);
                        bvScriptItem.setItemFileType(ScriptItemFileType.FOLDER.getCode());
                        String fileName = keys[3];
                        ScriptItemFileType scriptItemType = ScriptItemFileType.getScriptItemTypeByCode(fileName);
                        if (!ScriptItemFileType.TXT.equals(scriptItemType)) {
                            bvScriptItem.setScriptContent(tempPath + File.separator + entry.getKey());
                        }
                        insertList.add(bvScriptItem);
                    }
                }
                bvScriptItemService.saveBatch(insertList);
            } else {
                throw new BusException("上传文件只支持zip格式");
            }
        } catch (Exception e) {
            log.error("上传失败", e);
            throw new BusException("上传失败");
        }
    }

    @Override
    public void removeCategory(Long[] ids) {
        if (ArrayUtil.isEmpty(ids)) {
            return;
        }

        List<BvScriptCategory> removeEntityList = Arrays.stream(ids).map(id -> {
            BvScriptCategory entity = new BvScriptCategory().setId(id);
            entity.setDelFlag(DelFlag.DELETED.getCode());
            entity.setDeleteTime(new Date());
            return entity;
        }).collect(Collectors.toList());

        for (BvScriptCategory bvScriptCategory : removeEntityList) {
            LambdaQueryWrapperExt<BvScriptItem> queryWrapperExt = new LambdaQueryWrapperExt<>();
            queryWrapperExt.eq(BvScriptItem::getScriptCategoryId, bvScriptCategory.getId());
            List<BvScriptItem> itemList = bvScriptItemService.list(queryWrapperExt);
            if (CollectionUtils.isEmpty(itemList)) {
                continue;
            }
            List<BvScriptItem> scriptItemUpdateList = itemList.stream().map(item -> {
                BvScriptItem entity = new BvScriptItem().setId(item.getId());
                item.setDelFlag(DelFlag.DELETED.getCode());
                item.setDeleteTime(new Date());
                return entity;
            }).collect(Collectors.toList());
            bvScriptItemService.updateBatchById(scriptItemUpdateList);
        }

        updateBatchById(removeEntityList);
    }

    @Override
    public void importSelectFolder(String path) {
        if (StringUtils.isBlank(path)) {
            return;
        }

        String[] split = path.split("\\\\");
        if (split.length < 2) {
            return;
        }
        String categoryName = split[split.length - 1];

        BvScriptCategory bvScriptCategory = new BvScriptCategory();
        bvScriptCategory.setScriptCategoryName(categoryName);
        bvScriptCategory.setPath(path);
        save(bvScriptCategory);

        File inputFolder = new File(path);
        Map<String, String> files = readFolderToMap(inputFolder);

        List<BvScriptItem> insertList = new ArrayList<>();
        for (Map.Entry<String, String> entry : files.entrySet()) {
            String[] keys = entry.getKey().split("/");

            // 验证路径格式有效性
            if (keys.length < 1) {
                log.error("路径格式错误，跳过条目：" + entry.getKey());
                continue;
            }
            String type = keys[0];          // 话术类型
            ScriptType scriptTypeByInfo = ScriptType.getScriptTypeByInfo(type);
            if (scriptTypeByInfo == null) {
                continue;
            }

            if (keys.length == 1) {
                BvScriptItem bvScriptItem = new BvScriptItem();
                bvScriptItem.setScriptCategoryId(bvScriptCategory.getId());
                bvScriptItem.setScriptType(scriptTypeByInfo.getCode());
                bvScriptItem.setScriptContent(entry.getValue());
                bvScriptItem.setItemName(type);
                bvScriptItem.setFilePath(entry.getKey());
                bvScriptItem.setItemFileType(ScriptItemFileType.getScriptItemTypeByCode(bvScriptItem.getItemName()).getCode());
                insertList.add(bvScriptItem);
            } else if (keys.length == 2) {
                BvScriptItem bvScriptItem = new BvScriptItem();
                bvScriptItem.setScriptCategoryId(bvScriptCategory.getId());
                bvScriptItem.setScriptType(scriptTypeByInfo.getCode());
                bvScriptItem.setItemName(keys[1]);
                ScriptItemFileType scriptItemType = ScriptItemFileType.getScriptItemTypeByCode(bvScriptItem.getItemName());
                bvScriptItem.setItemFileType(scriptItemType.getCode());
                if (ScriptItemFileType.TXT.equals(scriptItemType)) {
                    bvScriptItem.setScriptContent(entry.getValue());
                } else {
                    //视频文件路径
                    bvScriptItem.setScriptContent(path + File.separator + entry.getKey());
                }
                bvScriptItem.setFilePath(entry.getKey());
                insertList.add(bvScriptItem);
            } else if (keys.length == 3 && ScriptType.MAIN_AUDIO.equals(scriptTypeByInfo)) {
                BvScriptItem bvScriptItem = new BvScriptItem();
                bvScriptItem.setScriptCategoryId(bvScriptCategory.getId());
                bvScriptItem.setScriptType(scriptTypeByInfo.getCode());
                //主音频下面的文件夹名称
                bvScriptItem.setItemName(keys[1]);
                bvScriptItem.setItemFileType(ScriptItemFileType.FOLDER.getCode());
                String fileName = keys[2];
                ScriptItemFileType scriptItemType = ScriptItemFileType.getScriptItemTypeByCode(fileName);
                if (!ScriptItemFileType.TXT.equals(scriptItemType)) {
                    bvScriptItem.setScriptContent(path + File.separator + entry.getKey());
                }
                bvScriptItem.setFilePath(entry.getKey());
                insertList.add(bvScriptItem);
            } else if (keys.length == 3 && ScriptType.MAIN_VIDEO.equals(scriptTypeByInfo)) {
                //主视频只会记录一个文件夹名称，播放的时候在文件夹中随机找一个视频播放
                Optional<BvScriptItem> first = insertList.stream().filter(item -> item.getItemName().equals(keys[1])
                        && item.getScriptType().equals(scriptTypeByInfo.getCode())
                        && item.getScriptCategoryId().equals(bvScriptCategory.getId())).findFirst();

                //只保存一条主视频记录，主视频下的所有视频路径拼接到一个字段中，逗号分割
                if (first.isPresent()) {
                    insertList.stream().filter(item -> item.getItemName().equals(keys[1])
                                    && item.getScriptType().equals(scriptTypeByInfo.getCode())
                                    && item.getScriptCategoryId().equals(bvScriptCategory.getId()))
                            .forEach(item -> {
                                String scriptContent = item.getScriptContent();
                                scriptContent += "," + path + File.separator + entry.getKey();
                                item.setScriptContent(scriptContent);
                            });
                } else {
                    BvScriptItem bvScriptItem = new BvScriptItem();
                    bvScriptItem.setScriptCategoryId(bvScriptCategory.getId());
                    bvScriptItem.setScriptType(scriptTypeByInfo.getCode());
                    //主视频下面的文件夹名称
                    bvScriptItem.setItemName(keys[1]);
                    bvScriptItem.setItemFileType(ScriptItemFileType.FOLDER.getCode());
                    String fileName = keys[2];
                    ScriptItemFileType scriptItemType = ScriptItemFileType.getScriptItemTypeByCode(fileName);
                    if (!ScriptItemFileType.TXT.equals(scriptItemType)) {
                        bvScriptItem.setScriptContent(path + File.separator + entry.getKey());
                    }
                    bvScriptItem.setFilePath(entry.getKey());
                    insertList.add(bvScriptItem);
                }
            }
        }
        if (CollectionUtils.isEmpty(insertList)) {
            throw new RuntimeException("话术文件格式不正确");
        }
        Optional<BvScriptItem> existMainAudio = insertList.stream().filter(item -> ScriptType.MAIN_AUDIO.getCode().equals(item.getScriptType())).findAny();
        if (!existMainAudio.isPresent()) {
            throw new RuntimeException("请检查话术文件，缺少主音频文件夹");
        }

        bvScriptItemService.saveBatch(insertList);

    }

    /**
     * 新增文件夹读取工具方法
     *
     * @param folder
     * @return
     * @throws IOException
     */
    private static Map<String, String> readFolderToMap(File folder) {
        Map<String, String> fileMap = new HashMap<>();
        Path basePath = folder.toPath();

        try {
            Files.walk(basePath)
                    .filter(Files::isRegularFile)
                    .forEach(filePath -> {
                        try {
                            // 生成相对路径作为key（统一用斜杠分隔）
                            String relativePath = basePath.relativize(filePath)
                                    .toString()
                                    .replace(File.separatorChar, '/');

                            // 判断文件类型处理内容
                            String value;
                            if (filePath.getFileName().toString().endsWith(".txt")) {
                                value = new String(Files.readAllBytes(filePath), StandardCharsets.UTF_8);
                            } else {
                                value = filePath.toAbsolutePath().toString();
                            }

                            fileMap.put(relativePath, value);
                        } catch (IOException e) {
                            log.error("文件读取失败: " + filePath, e);
                        }
                    });
        } catch (IOException e) {
            log.error("目录遍历失败: " + basePath, e);
        }

        return fileMap;
    }
}
